package com.project.ujob.config;

import java.util.HashMap;
import java.util.Map;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.MapPropertySource;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.project.ujob.properties.RedisProperties;

@Configuration
@EnableCaching
@ImportAutoConfiguration({ RedisProperties.class })
public class RedisCacheConfig {

	private RedisProperties redisProperties;

	RedisCacheConfig(RedisProperties redisProperties) {
		this.redisProperties = redisProperties;
	}

	@Bean
	public CacheManager cacheManager(RedisTemplate<String, String> redisTemplate) {
		RedisCacheManager rcm = RedisCacheManager.create(lettuceConnectionFactory());
		return rcm;
	}

	@Bean
	public RedisTemplate<String, String> redisTemplate() {
		RedisConnectionFactory factory = lettuceConnectionFactory();
		StringRedisTemplate template = new StringRedisTemplate(factory);
		@SuppressWarnings("unchecked")
		Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
		ObjectMapper om = new ObjectMapper();
		om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
		om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
		jackson2JsonRedisSerializer.setObjectMapper(om);
		template.setKeySerializer(new StringRedisSerializer());
		template.setValueSerializer(jackson2JsonRedisSerializer);

		template.afterPropertiesSet();
		return template;
	}

	@Bean
	public RedisConnectionFactory lettuceConnectionFactory() {
		String nodes = redisProperties.getNodes();
		String[] nodeArray = nodes.split(",");
		if (nodeArray.length > 1) {
			Map<String, Object> source = new HashMap<String, Object>();
			source.put("spring.redis.cluster.nodes", redisProperties.getNodes());
			source.put("spring.redis.cluster.timeout", redisProperties.getTimeout());
			source.put("spring.redis.cluster.max-redirects", redisProperties.getMaxRedirect());

			RedisClusterConfiguration redisClusterConfiguration;
			redisClusterConfiguration = new RedisClusterConfiguration(
					new MapPropertySource("RedisClusterConfiguration", source));
			return new LettuceConnectionFactory(redisClusterConfiguration);
		} else {
			RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
			redisStandaloneConfiguration.setHostName(nodes.split(":")[0]);
			redisStandaloneConfiguration.setPort(Integer.parseInt(nodes.split(":")[1]));
			return new LettuceConnectionFactory(redisStandaloneConfiguration);
		}

	}

	@Bean
	public GenericObjectPoolConfig genericObjectPoolConfig() {
		GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
		genericObjectPoolConfig.setMaxIdle(redisProperties.getMaxIdle());
		genericObjectPoolConfig.setMinIdle(redisProperties.getMinIdle());
		genericObjectPoolConfig.setMaxTotal(redisProperties.getMaxTotal());
		genericObjectPoolConfig.setMaxWaitMillis(redisProperties.getMaxWait());
		return genericObjectPoolConfig;
	}

}
